package com.cloud.rou.im.connection.service;

import com.cloud.rou.im.connection.ChannelHandlerContextFactory;
import com.cloud.rou.im.connection.container.connection.UserIdAttributeKey;
import com.cloud.rou.im.connection.container.manager.SessionManager;
import com.cloud.rou.im.connection.container.manager.SessionManagerHolder;
import com.cloud.rou.im.connection.container.session.Session;
import com.cloud.rou.im.connection.userstatus.UserStatusService;
import com.cloud.rou.im.connection.userstatus.UserStatusServiceImpl;
import com.cloud.rou.im.msg.ClientMsg;
import com.cloud.rou.im.msg.LoginMsg;
import com.cloud.rou.im.msg.Msg;
import com.cloud.rou.im.msg.MsgFactory;
import com.cloud.rou.im.msg.enumtype.AckType;
import com.cloud.rou.im.msg.enumtype.MsgType;
import com.cloud.rou.im.protocol.transfer.DataPacketFactory;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;

/**
 * <p></p>
 *
 * @author GaoShuangWen
 * @since 2019-11-09 20:41
 */
@Slf4j
public class ConnectorService {

    private SessionManager manager  ;

    public ConnectorService() {
       this.manager =SessionManagerHolder.getManager();
    }

    /**
     * Process the chat message and forward it to the next client
     *
     * @param msg
     */
    public void doChatForward(ChannelHandlerContext ctx, Msg msg) {
        if(ctx==ChannelHandlerContextFactory.getCtx()){
            Session session = manager.getConnectSessionByUserId(msg.getRecipientId());
            if (session != null ) {
                doWriteAndFlush(session.getConnection().getCtx(),msg);
            }
            return;
        }
        if(checkSession(ctx,msg)){
            Msg ackMsg = MsgFactory.chatToAck(() -> AckType.DELIVERED,msg);
            doSendReceiptAck(ctx,ackMsg);
            Session session = manager.getConnectSessionByUserId(msg.getRecipientId());
            if (session == null ) {
                //todo: if not on the machine
                log.error("[send ack to client] not one the machine, userId: {}",
                        msg.getRecipientId());

                doWriteAndFlush(ChannelHandlerContextFactory.getCtx(),msg);
                return;
            }
             doWriteAndFlush(session.getConnection().getCtx(),msg);

        }

    }
    public void doLogin(ChannelHandlerContext ctx, Msg msg) {
       if(msg instanceof ClientMsg){
           ClientMsg clientMsg = (ClientMsg) msg;
           if(clientMsg.getMsgType() == MsgType.LOGIN){
               // TODO check login
               UserStatusService statusService = new UserStatusServiceImpl();
               // 上线
               statusService.online(msg.getSenderId(), ctx);
               Msg ackMsg = MsgFactory.chatToAck(() -> AckType.LOGIN_SUCCESS,msg);
               System.out.println("已经发送登录成功回执消息");
              // doSendReceiptAck(ctx,ackMsg);
               doWriteAndFlush(ctx,ackMsg);
           }

           if(msg.getSenderId().equals(999L)){
               // 路由
               ChannelHandlerContextFactory.add(ctx);
               return;
           }

       }
    }

    /**
     * Message delivery receipt
     *
     * @param msg
     */
    public void doSendReceiptAck(ChannelHandlerContext ctx, Msg msg) {
       Session session = manager.getConnectSessionByUserId(msg.getRecipientId());
        if (session == null) {
            //todo: if not on the machine
            log.error("[send ack msg to client] not one the machine, userId: {}",
                    msg.getRecipientId());
            return;
        }
        doWriteAndFlush(session.getConnection().getCtx(),msg);
        // todo 修改消息状态为已读
    }


    private ChannelFuture doWriteAndFlush(ChannelHandlerContext ctx, Msg msg) {
        return ctx.writeAndFlush(DataPacketFactory.getPacket(msg));
    }
    private void doClose(ChannelHandlerContext ctx) {
        ctx.close();
    }

    private boolean checkSession(ChannelHandlerContext ctx,Msg msg) {
        if(ctx==ChannelHandlerContextFactory.getCtx()){
            return true;
        }
        Long userId = ctx.channel().attr(UserIdAttributeKey.USER_ID).get();
        if(userId==null|| !msg.getSenderId().equals(userId)){
            log.error("非法的msg");
            // throw new Exception("非法的ctx");
            // doClose(ctx);
            return false;
        }
        return true;
    }
}
